package com.techfansy.photo;


import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;


/**
 * 底图缩放，浮层不�?
 * @author yfren
 */
public class CCropImageView extends View {
	private static final String TAG = "CCropImageView";

	// 单点触摸的时�?
	private float oldX = 0;
	private float oldY = 0;

	// 多点触摸的时�?
	private float oldx_0 = 0;
	private float oldy_0 = 0;

	private float oldx_1 = 0;
	private float oldy_1 = 0;

	// 状�?
	private static final int STATUS_Touch_SINGLE = 1;// 单点
	private static final int STATUS_TOUCH_MULTI_START = 2;// 多点�?��
	private static  final int STATUS_TOUCH_MULTI_TOUCHING = 3;// 多点拖拽�?

	private int mStatus = STATUS_Touch_SINGLE;

	// 默认的裁剪图片宽度与高度
	private static final int defaultCropWidth = 500;
	private  static final int defaultCropHeight = 500;
	private int cropWidth = defaultCropWidth;
	private int cropHeight = defaultCropHeight;

	protected float oriRationWH = 0;// 原始宽高比率
	protected float maxZoomOut = 100.0f;// �?��扩大到多少�?
	protected float minZoomIn = 0.111111f;// �?��缩小到多少�?
	protected static final float zoomRatio = UIUtils.getScreenWidth()/3; //计算缩放比例时的系数
	protected float touchSlop;

	protected Drawable mDrawable;// 原图
	protected FloatDrawable mFloatDrawable;// 浮层
	protected Rect mDrawableSrc = new Rect();
	protected Rect mDrawableDst = new Rect();
	protected Rect mDrawableFloat = new Rect();// 浮层选择框，就是头像选择�?
	protected boolean isFrist = true;

	protected Context mContext;

	public CCropImageView(Context context) {
		super(context);
		init(context);
	}

	public CCropImageView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context);
	}

	public CCropImageView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init(context);

	}

	@SuppressLint("NewApi")
	private void init(Context context) {
		setBackgroundColor(Color.parseColor("#33000000"));
		this.mContext = context;
		try {
			if (android.os.Build.VERSION.SDK_INT >= 11) {
				this.setLayerType(LAYER_TYPE_SOFTWARE, null);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		mFloatDrawable = new FloatDrawable();// 头像选择�?
		touchSlop = ViewConfiguration.get(context).getScaledTouchSlop() / 3;
	}

	public void setDrawable(Drawable mDrawable, int cropWidth, int cropHeight) {
		this.mDrawable = mDrawable;
		this.cropWidth = cropWidth;
		this.cropHeight = cropHeight;
//		Log.d("miaoyu", "CCropImageView setDrawable cropWidth = " + cropWidth + " cropHeight = " + cropHeight);
		this.isFrist = true;
		invalidate();
	}

	private boolean isDependHeight;

	@Override
	public boolean onTouchEvent(MotionEvent event) {

		if (event.getPointerCount() > 1) {
			if (mStatus == STATUS_Touch_SINGLE) {
				mStatus = STATUS_TOUCH_MULTI_START;

				oldx_0 = event.getX(0);
				oldy_0 = event.getY(0);

				oldx_1 = event.getX(1);
				oldy_1 = event.getY(1);
			} else if (mStatus == STATUS_TOUCH_MULTI_START) {
				float newx_0 = event.getX(0);
				float newy_0 = event.getY(0);

				float newx_1 = event.getX(1);
				float newy_1 = event.getY(1);

				if(checkSlop(oldx_0, oldx_1, oldy_0, oldy_1, newx_0, newx_1, newy_0, newy_1)){
					mStatus = STATUS_TOUCH_MULTI_TOUCHING;

					float oldWidth = Math.abs(oldx_1 - oldx_0);
					float oldHeight = Math.abs(oldy_1 - oldy_0);

					float newWidth = Math.abs(newx_1 - newx_0);
					float newHeight = Math.abs(newy_1 - newy_0);
					isDependHeight = Math.abs(newHeight - oldHeight) > Math
							.abs(newWidth - oldWidth);
					Log.e(TAG, "isDependHeight = " + isDependHeight
							+ " newHeight = " + newHeight + " oldHeight = " + oldHeight
							+ " newWidth = " + newWidth + " oldWidth = " + oldWidth);
				}
			}
		} else {
			if (mStatus == STATUS_TOUCH_MULTI_START
					|| mStatus == STATUS_TOUCH_MULTI_TOUCHING) {
				oldx_0 = 0;
				oldy_0 = 0;

				oldx_1 = 0;
				oldy_1 = 0;

				oldX = event.getX();
				oldY = event.getY();
			}

			mStatus = STATUS_Touch_SINGLE;
		}

		// Log.v("count currentTouch"+currentTouch, "-------");

		switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				// Log.v("count ACTION_DOWN", "-------");
				oldX = event.getX();
				oldY = event.getY();
				break;

			case MotionEvent.ACTION_UP:
				// Log.v("count ACTION_UP", "-------");
				checkBounds();
				break;

			case MotionEvent.ACTION_POINTER_UP:
				// Log.v("count ACTION_POINTER_UP", "-------");
				break;

			case MotionEvent.ACTION_MOVE:
				// Log.v("count ACTION_MOVE", "-------");
				if (mStatus == STATUS_TOUCH_MULTI_TOUCHING) {
					float newx_0 = event.getX(0);
					float newy_0 = event.getY(0);

					float newx_1 = event.getX(1);
					float newy_1 = event.getY(1);

					float oldWidth = Math.abs(oldx_1 - oldx_0);
					float oldHeight = Math.abs(oldy_1 - oldy_0);

					float newWidth = Math.abs(newx_1 - newx_0);
					float newHeight = Math.abs(newy_1 - newy_0);

//				boolean isDependHeight = Math.abs(newHeight - oldHeight) > Math
//						.abs(newWidth - oldWidth);
//
//				float ration = isDependHeight ? ((float) newHeight / (float) oldHeight)
//						: ((float) newWidth / (float) oldWidth);
					float zoomDistance = isDependHeight ? (newHeight - oldHeight) : (newWidth - oldWidth);
					float ration = 1 + zoomDistance/zoomRatio;

					Log.e(TAG, "ration = " + ration + " zoomDistance = " + zoomDistance
							+ " newHeight = " + newHeight + " oldHeight = " + oldHeight
							+ " newWidth = " + newWidth + " oldWidth = " + oldWidth);

					int centerX = mDrawableDst.centerX();
					int centerY = mDrawableDst.centerY();
					int _newWidth = (int) (mDrawableDst.width() * ration);
					int _newHeight = (int) ((float) _newWidth / oriRationWH);

					float tmpZoomRation = (float) _newWidth
							/ (float) mDrawableSrc.width();
					if (tmpZoomRation >= maxZoomOut) {
						_newWidth = (int) (maxZoomOut * mDrawableSrc.width());
						_newHeight = (int) ((float) _newWidth / oriRationWH);
					} else if (tmpZoomRation <= minZoomIn) {
						_newWidth = (int) (minZoomIn * mDrawableSrc.width());
						_newHeight = (int) ((float) _newWidth / oriRationWH);
					}

					oldx_0 = newx_0;
					oldy_0 = newy_0;

					oldx_1 = newx_1;
					oldy_1 = newy_1;

//				if (_newWidth < mDrawableFloat.width()
//						|| _newHeight < mDrawableFloat.height()) {
//					break;
//				}

					mDrawableDst.set(centerX - _newWidth / 2, centerY - _newHeight
							/ 2, centerX + _newWidth / 2, centerY + _newHeight / 2);
					invalidate();

//				Log.e("width():" + (mDrawableSrc.width()) + "height():"
//						+ (mDrawableSrc.height()), "new width():"
//						+ (mDrawableDst.width()) + "new height():"
//						+ (mDrawableDst.height()));
//				Log.e("" + (float) mDrawableSrc.height()
//						/ (float) mDrawableSrc.width(),
//						"mDrawableDst:" + (float) mDrawableDst.height()
//								/ (float) mDrawableDst.width());

				} else if (mStatus == STATUS_Touch_SINGLE) {
					int dx = (int) (event.getX() - oldX);
					int dy = (int) (event.getY() - oldY);

					oldX = event.getX();
					oldY = event.getY();

					if (!(dx == 0 && dy == 0)) {
						mDrawableDst.offset((int) dx, (int) dy);
						invalidate();
					}
				}
				break;
		}

		return true;
	}

	private boolean checkSlop(float old_x0, float old_x1, float old_y0, float old_y1,
							  float new_x0, float new_x1, float new_y0, float new_y1){
		float oldDistance = calDistance(old_x0, old_x1, old_y0, old_y1);
		float newDistance = calDistance(new_x0, new_x1, new_y0, new_y1);
		return Math.abs(oldDistance - newDistance) >= touchSlop;
	}

	private float calDistance(float x0, float x1, float y0, float y1){
		return (float) Math.sqrt((x0 - x1) * (x0 - x1) + (y0 - y1) * (y0 - y1));
	}

	@Override
	protected void onDraw(Canvas canvas) {
		if (mDrawable == null) {
			return; // couldn't resolve the URI
		}

		if (mDrawable.getIntrinsicWidth() == 0
				|| mDrawable.getIntrinsicHeight() == 0) {
			return; // nothing to draw (empty bounds)
		}
		configureBounds();
		mDrawable.draw(canvas);
		canvas.save();
		canvas.clipRect(mDrawableFloat, Region. Op.DIFFERENCE);
		canvas.drawColor(Color.parseColor("#33000000"));//背景图片颜色
		canvas.restore();
		mFloatDrawable.draw(canvas);
	}

	protected void configureBounds() {
		if (isFrist) {
			oriRationWH = ((float) mDrawable.getIntrinsicWidth())
					/ ((float) mDrawable.getIntrinsicHeight());

			final float scale = mContext.getResources().getDisplayMetrics().density;
			int w = Math.min(getWidth(), (int) (mDrawable.getIntrinsicWidth()
					* scale + 0.5f));
			int h = (int) (w / oriRationWH);

			int left = (getWidth() - w) / 2;
			int top = (getHeight() - h) / 2;
			int right = left + w;
			int bottom = top + h;

			mDrawableSrc.set(left, top, right, bottom);
			mDrawableDst.set(mDrawableSrc);

			int floatWidth = dipTopx(mContext, cropWidth);
			int floatHeight = dipTopx(mContext, cropHeight);

			if (floatWidth > getWidth()) {
				floatWidth = getWidth();
				floatHeight = cropHeight * floatWidth / cropWidth;
			}

			if (floatHeight > getHeight()) {
				floatHeight = getHeight();
				floatWidth = cropWidth * floatHeight / cropHeight;
			}

			int floatLeft = (getWidth() - floatWidth-400) / 2;
			int floatTop = (getHeight() - floatHeight-400) / 2;
			mDrawableFloat.set(floatLeft, floatTop, floatLeft + floatWidth+400,
					floatTop + floatHeight+400);

			float widthMaxZoom = (mDrawableDst.width() >= mDrawableFloat.width()) ?
					3 : Math.max((float)mDrawableFloat.width()/mDrawableDst.width(), 3);
			float heightMaxZoom = (mDrawableDst.height() >= mDrawableFloat.height()) ?
					3 : Math.max((float)mDrawableFloat.height()/mDrawableDst.height(), 3);
			maxZoomOut = Math.max(widthMaxZoom, heightMaxZoom);

			float widthMinZoom = (mDrawableDst.width() >= mDrawableFloat.width()) ?
					Math.max((float)mDrawableFloat.width()/mDrawableDst.width(), 1f/3) : 1;
			float heightMinZoom = (mDrawableDst.height() >= mDrawableFloat.height()) ?
					Math.max((float)mDrawableFloat.height()/mDrawableDst.height(), 1f/3) : 1;
			minZoomIn = Math.max(widthMinZoom, heightMinZoom);

			isFrist = false;
		}

		mDrawable.setBounds(mDrawableDst);
		mFloatDrawable.setBounds(mDrawableFloat);
	}

	protected void checkBounds() {
		int newLeft = mDrawableDst.left;
		int newTop = mDrawableDst.top;

		boolean isChange = false;
		if (mDrawableDst.left < -mDrawableDst.width()) {
			newLeft = -mDrawableDst.width();
			isChange = true;
		}

		if (mDrawableDst.top < -mDrawableDst.height()) {
			newTop = -mDrawableDst.height();
			isChange = true;
		}

		if (mDrawableDst.left > getWidth()) {
			newLeft = getWidth();
			isChange = true;
		}

		if (mDrawableDst.top > getHeight()) {
			newTop = getHeight();
			isChange = true;
		}

		if(mDrawableFloat.height() <= mDrawableDst.height()){
			if (mDrawableFloat.top < mDrawableDst.top) {
				newTop = mDrawableFloat.top;
				isChange = true;
			}

			if (mDrawableFloat.bottom > mDrawableDst.bottom) {
				newTop = mDrawableDst.top + mDrawableFloat.bottom - mDrawableDst.bottom;
				isChange = true;
			}
		} else{
			if (mDrawableFloat.top > mDrawableDst.top) {
				newTop = mDrawableFloat.top;
				isChange = true;
			}

			if (mDrawableFloat.bottom < mDrawableDst.bottom) {
				newTop = mDrawableDst.top + mDrawableFloat.bottom - mDrawableDst.bottom;
				isChange = true;
			}
		}

		if(mDrawableFloat.width() <= mDrawableDst.width()){
			if (mDrawableFloat.left < mDrawableDst.left) {
				newLeft = mDrawableFloat.left;
				isChange = true;
			}

			if (mDrawableFloat.right > mDrawableDst.right) {
				newLeft = mDrawableDst.left + mDrawableFloat.right - mDrawableDst.right;
				isChange = true;
			}
		} else{
			if (mDrawableFloat.left > mDrawableDst.left) {
				newLeft = mDrawableFloat.left;
				isChange = true;
			}

			if (mDrawableFloat.right < mDrawableDst.right) {
				newLeft = mDrawableDst.left + mDrawableFloat.right - mDrawableDst.right;
				isChange = true;
			}
		}

		mDrawableDst.offsetTo(newLeft, newTop);
		if (isChange) {
			invalidate();
		}
	}

	public Bitmap getCropImage() {

		Bitmap tmpBitmap = Bitmap.createBitmap(getWidth(), getHeight(),
				Config.RGB_565);
		Canvas canvas = new Canvas(tmpBitmap);
		canvas.drawColor(Color.WHITE);
		mDrawable.draw(canvas);

		Matrix matrix = new Matrix();
		float scale = (float) (mDrawableSrc.width())
				/ (float) (mDrawableDst.width());
		matrix.postScale(scale, scale);

		Bitmap ret = Bitmap.createBitmap(tmpBitmap, mDrawableFloat.left,
				mDrawableFloat.top, mDrawableFloat.width(),
				mDrawableFloat.height(), matrix, true);

		tmpBitmap.recycle();
		tmpBitmap = null;

		Bitmap newRet = Bitmap.createScaledBitmap(ret, cropWidth, cropHeight,
				false);
		ret.recycle();
		ret = newRet;
		Log.e(TAG, "getCropImage done");

		return ret;
	}

	public int dipTopx(Context context, float dpValue) {
		return (int) dpValue;
	}
}
